home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Documentation / d e v e l o p / Develop Issue 23 article / Geometry Sample / QD3D src / Quickdraw3DSupport.c < prev    next >
Encoding:
Text File  |  1997-08-14  |  20.3 KB  |  727 lines  |  [TEXT/MPCC]

  1.  
  2.  
  3. // for QuickDraw 3D
  4. #include "QD3D.h"
  5. #include "QD3DMath.h"
  6. #include "QD3DAcceleration.h"
  7. #include "QD3DDrawContext.h"
  8. #include "QD3DShader.h"
  9. #include "QD3DLight.h"
  10. #include "QD3DRenderer.h"
  11. #include "QD3DTransform.h"
  12. #include "QD3DGroup.h"
  13. #include "QD3DCamera.h"
  14.  
  15.  
  16. #include "Geometries.h"
  17. #include "MyErrorHandler.h"
  18. #include "Quickdraw3DSupport.h"
  19.  
  20.  
  21.  
  22. //-----------------------------------------------------------------------
  23. // local utility functions
  24. void GetGroupBBox(DocumentHdl theDocument, TQ3BoundingBox *viewBBox);                                                
  25. static TQ3Status GetDocumentGroupBoundingBox(DocumentHdl theDocument, 
  26.                     TQ3BoundingBox *viewBBox) ;
  27.  
  28.  
  29. //-----------------------------------------------------------------------
  30.  
  31. DocumentHdl GetDocumentHdl(WindowObjHndl obj)
  32. {
  33.     check(obj != NULL);
  34.     check((*obj)->refCon != NULL);
  35.     
  36.     return (DocumentHdl) (*obj)->refCon;
  37. }
  38.  
  39. //-----------------------------------------------------------------------
  40. // Call this after initializing the Toolbox, but before entering
  41. // the main event loop.
  42. //-----------------------------------------------------------------------
  43. void InitQuickDraw3DSupport(void)
  44. {
  45.     //
  46.     // Initialize QuickDraw 3D, open a connection to QuickDraw 3D
  47.     //
  48.     if (Q3Initialize() == kQ3Failure) {
  49.         DebugStr("\pErInitialize returned failure.");    
  50.         ExitToShell() ;
  51.     }
  52.  
  53.     //
  54.     // install the error handler - this gets called whenever
  55.     // an error occurs, which means we don't have to check so much
  56.     //
  57.     Q3Error_Register(MyErrorHandler, 0L);        
  58.     Q3Warning_Register(MyWarningHandler, 0L);
  59. }
  60.  
  61. //-----------------------------------------------------------------------
  62. // Call this after dropping out of the main event loop.
  63. //-----------------------------------------------------------------------
  64. void TeardownQuickDraw3DSupport(void)
  65. {    
  66.     //
  67.     //    Close our connection to the QuickDraw 3D library
  68.     //
  69.     if (Q3Exit() == kQ3Failure) DebugStr("\pErExit returned failure.");
  70. }
  71.  
  72. //-----------------------------------------------------------------------
  73.  
  74. void InitDocumentData(WindowPtr win, DocumentHdl theDocument) 
  75. {
  76.     TQ3Point3D        myOrigin = { 0, 0, 0 } ;
  77.     
  78.     check(theDocument != NULL);
  79.         
  80.     // Lock and load
  81.     HLock((Handle)theDocument);
  82.     
  83.     // sets up the 3d data for the scene
  84.     // Create view for QuickDraw 3D.
  85.     (**theDocument).fView = MyNewView(win);
  86.  
  87.     // the main display group:
  88.     (**theDocument).fModel = NULL ;    
  89.     
  90.     // the drawing styles:
  91.     (**theDocument).fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleNone) ;
  92.     (**theDocument).fBackFacing = Q3BackfacingStyle_New(kQ3BackfacingStyleBoth);
  93.     (**theDocument).fFillStyle = Q3FillStyle_New(kQ3FillStyleFilled);
  94.  
  95.     (**theDocument).fGroupScale = 1;                
  96.     (**theDocument).fGroupCenter = myOrigin ;    
  97.     
  98.     // set up an illumination shder for this document
  99.     (**theDocument).fShader = Q3PhongIllumination_New() ;
  100.     
  101.     // set a default style for this document        
  102.     (**theDocument).fCurrentInterpolation = kQ3InterpolationStyleNone ;
  103.  
  104.     // set the rotation matrix the identity matrix
  105.     Q3Matrix4x4_SetIdentity(&(**theDocument).fRotation);    
  106.                 
  107.     // unlock the handle            
  108.     HUnlock((Handle) theDocument) ;
  109. }
  110.  
  111. //-----------------------------------------------------------------------
  112.  
  113. void DisposeDocumentData(DocumentHdl theDocument)
  114. {
  115.     // Lock and load
  116.     check(theDocument != NULL);
  117.     HLock((Handle)theDocument);
  118.     
  119.     if ((**theDocument).fView) 
  120.         Q3Object_Dispose((**theDocument).fView) ;                // the view for the scene
  121.  
  122.     if ((**theDocument).fModel)  
  123.         Q3Object_Dispose((**theDocument).fModel) ;                // object in the scene being modelled
  124.  
  125.     if ((**theDocument).fInterpolation)  
  126.         Q3Object_Dispose((**theDocument).fInterpolation) ;        // interpolation style used when rendering
  127.  
  128.     if ((**theDocument).fBackFacing)  
  129.         Q3Object_Dispose((**theDocument).fBackFacing) ;            // whether to draw shapes that face away from the camera
  130.  
  131.     if ((**theDocument).fFillStyle)  
  132.         Q3Object_Dispose((**theDocument).fFillStyle) ;            // whether drawn as solid filled object or decomposed to components
  133.  
  134.     HUnlock((Handle) theDocument) ;
  135.     
  136.     // And free the storage used by the document handle
  137.     DisposeHandle((Handle) theDocument);
  138. }
  139.  
  140. //-----------------------------------------------------------------------
  141. // Create and init a document with the 3d stuff - gets called 
  142. // by both open and new
  143. //-----------------------------------------------------------------------
  144. DocumentHdl    CreateDocument(WindowPtr win) 
  145. {
  146.     DocumentHdl        theDocument;
  147.     
  148.     theDocument = (DocumentHdl) NewHandleClear(sizeof(DocumentRec));
  149.     require(theDocument != NULL, NewHandleClearFailed);
  150.     
  151.     // initialise our document structure
  152.     InitDocumentData(win, theDocument);
  153.  
  154. NewHandleClearFailed:    
  155.     return theDocument;
  156. }
  157.  
  158. //-----------------------------------------------------------------------
  159. // Submit the scene for rendering/fileIO and picking
  160. //-----------------------------------------------------------------------
  161. TQ3Status SubmitScene(DocumentHdl theDocument) 
  162. {        
  163.     TQ3Vector3D                globalScale;
  164.     TQ3Vector3D                globalTranslate;
  165.     
  166.     globalScale.x = globalScale.y = globalScale.z = (**theDocument).fGroupScale;
  167.     globalTranslate = *(TQ3Vector3D *)&(**theDocument).fGroupCenter;
  168.     Q3Vector3D_Scale(&globalTranslate, -1, &globalTranslate);
  169.     Q3Style_Submit((**theDocument).fInterpolation, (**theDocument).fView);
  170.     Q3Style_Submit((**theDocument).fBackFacing , (**theDocument).fView);
  171.     Q3Style_Submit((**theDocument).fFillStyle, (**theDocument).fView);
  172.     
  173.     Q3InterpolationStyle_Submit((**theDocument).fCurrentInterpolation, (**theDocument).fView);
  174.         
  175.     Q3MatrixTransform_Submit( &(**theDocument).fRotation, (**theDocument).fView);
  176.         
  177.     Q3ScaleTransform_Submit(&globalScale, (**theDocument).fView);
  178.     Q3TranslateTransform_Submit(&globalTranslate, (**theDocument).fView);
  179.     
  180.     Q3Shader_Submit( (**theDocument).fShader, (**theDocument).fView ) ;
  181.     Q3DisplayGroup_Submit( (**theDocument).fModel, (**theDocument).fView);
  182.     
  183.     return kQ3Success ;
  184. }
  185.  
  186. //-----------------------------------------------------------------------
  187.  
  188. static TQ3Status GetDocumentGroupBoundingBox( 
  189.     DocumentHdl theDocument , 
  190.     TQ3BoundingBox *viewBBox)
  191. {
  192.     TQ3Status        status;
  193.     TQ3ViewStatus    viewStatus ;
  194.     
  195.     status = Q3View_StartBoundingBox( (**theDocument).fView, kQ3ComputeBoundsApproximate );
  196.     do {
  197.         Q3DisplayGroup_Submit( (**theDocument).fModel, (**theDocument).fView);
  198.     } while((viewStatus = Q3View_EndBoundingBox( (**theDocument).fView, viewBBox )) == kQ3ViewStatusRetraverse );
  199.     return status ;
  200. }
  201.  
  202. //-----------------------------------------------------------------------
  203.  
  204. TQ3ViewObject MyNewView(WindowPtr theWindow)
  205. {
  206.     TQ3Status                myStatus;
  207.     TQ3ViewObject            myView;
  208.     TQ3DrawContextObject        myDrawContext;
  209.     TQ3RendererObject        myRenderer;
  210.     TQ3CameraObject            myCamera;
  211.     TQ3GroupObject            myLights;
  212.     
  213.     myView = Q3View_New();
  214.     
  215.     //    Create and set draw context.
  216.     if ((myDrawContext = MyNewDrawContext(theWindow)) == nil )
  217.         goto bail;
  218.         
  219.     if ((myStatus = Q3View_SetDrawContext(myView, myDrawContext)) == kQ3Failure )
  220.         goto bail;
  221.  
  222.     Q3Object_Dispose( myDrawContext ) ;
  223.     
  224.     // Create and set renderer.
  225.     //
  226.     // hacky way to do this, but since I wanted these snippets to have 
  227.     // a minimal interface, this will suffice
  228.     //
  229.     // change the next line to “#if 1” to use the WF renderer
  230.     
  231. #if 0
  232.     // this would use the wireframe renderer
  233.     myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame);
  234.     if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  235.         goto bail;
  236.     }
  237. #else
  238.     // this would use the interactive software renderer
  239.  
  240.     if ((myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive)) != nil ) {
  241.         if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  242.             goto bail;
  243.         }
  244.     }
  245.     else {
  246.         goto bail;
  247.     }
  248. #endif
  249.  
  250.     Q3Object_Dispose(myRenderer);
  251.     
  252.     //    Create and set camera.
  253.     if ( (myCamera = MyNewCamera(theWindow)) == nil )
  254.         goto bail;
  255.         
  256.     if ((myStatus = Q3View_SetCamera(myView, myCamera)) == kQ3Failure )
  257.         goto bail;
  258.  
  259.     Q3Object_Dispose( myCamera ) ;
  260.     
  261.     //    Create and set lights.
  262.     if ((myLights = MyNewLights()) == nil )
  263.         goto bail;
  264.         
  265.     if ((myStatus = Q3View_SetLightGroup(myView, myLights)) == kQ3Failure )
  266.         goto bail;
  267.         
  268.     Q3Object_Dispose(myLights);
  269.  
  270.     //    Done!!!
  271.     return ( myView );
  272.     
  273. bail:
  274.     //    If any of the above failed, then don't return a view.
  275.     return ( nil );
  276. }
  277.  
  278. //-----------------------------------------------------------------------
  279.  
  280. TQ3DrawContextObject MyNewDrawContext(WindowPtr theWindow)
  281. {
  282.     TQ3DrawContextData        myDrawContextData;
  283.     TQ3MacDrawContextData    myMacDrawContextData;
  284.     TQ3ColorARGB            ClearColor;
  285.     TQ3DrawContextObject    myDrawContext ;
  286.     
  287.     ClearColor.a = 1.0;
  288.     ClearColor.r = 1.0;
  289.     ClearColor.g = 1.0;
  290.     ClearColor.b = 1.0;
  291.     
  292.     //    Fill in draw context data.
  293.     myDrawContextData.clearImageMethod = kQ3ClearMethodWithColor;
  294.     myDrawContextData.clearImageColor = ClearColor;
  295.     
  296.     myDrawContextData.paneState = kQ3False;
  297.     myDrawContextData.maskState = kQ3False;
  298.     
  299.     myDrawContextData.doubleBufferState = kQ3True;
  300.  
  301.     myMacDrawContextData.drawContextData = myDrawContextData;
  302.     
  303.     myMacDrawContextData.window = (CGrafPtr) theWindow;        // this is the window associated with the view
  304.     myMacDrawContextData.library = kQ3Mac2DLibraryNone;
  305.     myMacDrawContextData.viewPort = nil;
  306.     myMacDrawContextData.grafPort = nil;
  307.     
  308.     //    Create draw context and return it, if it’s nil the caller must handle
  309.     myDrawContext = Q3MacDrawContext_New(&myMacDrawContextData) ;
  310.  
  311.     return myDrawContext ;
  312. }
  313.  
  314. //-----------------------------------------------------------------------
  315.  
  316. TQ3CameraObject MyNewCamera(WindowPtr theWindow)
  317. {
  318.     TQ3CameraObject                    myCamera;
  319.     TQ3CameraData                    myCameraData;
  320.     TQ3ViewAngleAspectCameraData        myViewAngleCameraData;
  321.     TQ3Point3D                        cameraFrom     = { 0.0, 0.0, 30.0 };
  322.     TQ3Point3D                        cameraTo     = { 0.0, 0.0, 0.0 };
  323.     TQ3Vector3D                        cameraUp     = { 0.0, 1.0, 0.0 };
  324.     
  325.     float                             fieldOfView = .52359333333;
  326.     float                             hither         = 0.001;
  327.     float                             yon         = 1000;
  328.     
  329.     //    Fill in camera data.
  330.     myCameraData.placement.cameraLocation = cameraFrom;
  331.     myCameraData.placement.pointOfInterest = cameraTo;
  332.     myCameraData.placement.upVector = cameraUp;
  333.     
  334.     myCameraData.range.hither = hither;
  335.     myCameraData.range.yon = yon;
  336.     
  337.     myCameraData.viewPort.origin.x = -1.0;
  338.     myCameraData.viewPort.origin.y = 1.0;
  339.     myCameraData.viewPort.width = 2.0;
  340.     myCameraData.viewPort.height = 2.0;
  341.     
  342.     myViewAngleCameraData.cameraData = myCameraData;
  343.     myViewAngleCameraData.fov = fieldOfView ;
  344.     
  345.     // set up the aspect ratio based on the window
  346.     myViewAngleCameraData.aspectRatioXToY =  
  347.             (float) (theWindow->portRect.right - theWindow->portRect.left) / 
  348.             (float) (theWindow->portRect.bottom - theWindow->portRect.top);
  349.  
  350.     myCamera = Q3ViewAngleAspectCamera_New(&myViewAngleCameraData);    
  351.     
  352.     //    Return the camera.
  353.     return ( myCamera );
  354. }
  355.  
  356. //-----------------------------------------------------------------------
  357.  
  358. TQ3GroupObject MyNewLights()
  359. {
  360.     TQ3GroupPosition            myGroupPosition;
  361.     TQ3GroupObject            myLightList;
  362.     TQ3LightData                myLightData;
  363.     TQ3PointLightData        myPointLightData;
  364.     TQ3DirectionalLightData    myDirectionalLightData;
  365.     TQ3LightObject            myAmbientLight, myPointLight, myFillLight;
  366.     TQ3Point3D                pointLocation = { -10.0, 0.0, 10.0 };
  367.     TQ3Vector3D                fillDirection = { 10.0, 0.0, 10.0 };
  368.     TQ3ColorRGB                WhiteLight = { 1.0, 1.0, 1.0 };
  369.     
  370.     //    Set up light data for ambient light.  This light data will be used for point and fill
  371.     //    light also.
  372.  
  373.     myLightData.isOn = kQ3True;
  374.     myLightData.color = WhiteLight;
  375.     
  376.     //    Create ambient light.
  377.     myLightData.brightness = .2;
  378.     myAmbientLight = Q3AmbientLight_New(&myLightData);
  379.     if ( myAmbientLight == nil )
  380.         goto bail;
  381.     
  382.     //    Create point light.
  383.     myLightData.brightness = 1.0;
  384.     myPointLightData.lightData = myLightData;
  385.     myPointLightData.castsShadows = kQ3False;
  386.     myPointLightData.attenuation = kQ3AttenuationTypeNone;
  387.     myPointLightData.location = pointLocation;
  388.     myPointLight = Q3PointLight_New(&myPointLightData);
  389.     if ( myPointLight == nil )
  390.         goto bail;
  391.  
  392.     //    Create fill light.
  393.     myLightData.brightness = .2;
  394.     myDirectionalLightData.lightData = myLightData;
  395.     myDirectionalLightData.castsShadows = kQ3False;
  396.     myDirectionalLightData.direction = fillDirection;
  397.     myFillLight = Q3DirectionalLight_New(&myDirectionalLightData);
  398.     if ( myFillLight == nil )
  399.         goto bail;
  400.  
  401.     //    Create light group and add each of the lights into the group.
  402.     myLightList = Q3LightGroup_New();
  403.     if ( myLightList == nil )
  404.         goto bail;
  405.     myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight);
  406.     if ( myGroupPosition == 0 )
  407.         goto bail;
  408.     myGroupPosition = Q3Group_AddObject(myLightList, myPointLight);
  409.     if ( myGroupPosition == 0 )
  410.         goto bail;
  411.     myGroupPosition = Q3Group_AddObject(myLightList, myFillLight);
  412.     if ( myGroupPosition == 0 )
  413.         goto bail;
  414.  
  415.     Q3Object_Dispose( myAmbientLight ) ;
  416.     Q3Object_Dispose( myPointLight ) ;
  417.     Q3Object_Dispose( myFillLight ) ;
  418.  
  419.     //    Done!
  420.     return ( myLightList );
  421.     
  422. bail:
  423.     //    If any of the above failed, then return nothing!
  424.     return ( nil );
  425. }
  426.  
  427. //-----------------------------------------------------------------------
  428.  
  429. void GetGroupBBox(DocumentHdl theDocument, TQ3BoundingBox *viewBBox)
  430. {
  431.     TQ3Point3D                     from     = { 0.0, 0.0, 1.0 };
  432.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  433.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  434.     
  435.     float                         fieldOfView = .52359333333;
  436.     float                         hither         =  0.5;
  437.     float                         yon         =  1.5;
  438.     TQ3GroupObject                mainGroup = (**theDocument).fModel ;
  439.  
  440.     TQ3Status                    status;
  441.     
  442.  
  443.     status = GetDocumentGroupBoundingBox( theDocument , viewBBox) ;
  444.                                         
  445.     //
  446.     //  If we have a point model, then the "viewBBox" would end up
  447.     //  being a "singularity" at the location of the point.  As
  448.     //  this bounding "box" is used in setting up the camera spec,
  449.     //  we get bogus input into Escher.
  450.     
  451.     {
  452.          float        xSize, ySize, zSize;
  453.         
  454.         xSize = viewBBox->max.x - viewBBox->min.x;
  455.         ySize = viewBBox->max.y - viewBBox->min.y;
  456.         zSize = viewBBox->max.z - viewBBox->min.z;
  457.  
  458.         if (xSize <= kQ3RealZero &&
  459.             ySize <= kQ3RealZero &&
  460.             zSize <= kQ3RealZero) {
  461.             
  462.             viewBBox->max.x += 0.0001;
  463.             viewBBox->max.y += 0.0001;
  464.             viewBBox->max.z += 0.0001;
  465.             
  466.             viewBBox->min.x -= 0.0001;
  467.             viewBBox->min.y -= 0.0001;
  468.             viewBBox->min.z -= 0.0001;
  469.         }
  470.     }
  471. }
  472.  
  473. //-----------------------------------------------------------------------
  474.  
  475. TQ3Point3D AdjustCamera(DocumentHdl theDocument,
  476.     short                winWidth,
  477.     short                winHeight)
  478. {
  479.     float                         fieldOfView;
  480.     float                         hither;
  481.     float                         yon;
  482.     TQ3CameraPlacement            placement;
  483.     TQ3CameraRange                range;
  484.     TQ3BoundingBox                 viewBBox;
  485.     long                         fromAxis;    
  486.     float                         maxDimension;
  487.      float                        xSize, ySize, zSize;
  488.     float                        weights[2] = { 0.5, 0.5 };
  489.     TQ3Point3D                    points[2];
  490.     TQ3Vector3D                     viewVector;
  491.     TQ3Vector3D                    normViewVector;
  492.     TQ3Vector3D                    eyeToFrontClip;
  493.     TQ3Vector3D                    eyeToBackClip;
  494.     float                        viewDistance;
  495.     TQ3Vector3D                    diagonalVector;
  496.     float                        ratio;
  497.     TQ3CameraObject                camera;
  498.     
  499.     TQ3ViewObject                theView = (**theDocument).fView ;
  500.     TQ3GroupObject                mainGroup = (**theDocument).fModel ;
  501.     
  502.     TQ3Point3D                    *documentGroupCenter = &(**theDocument).fGroupCenter ;
  503.     float                        *documentGroupScale  = &(**theDocument).fGroupScale ;
  504.  
  505.     Q3View_GetCamera( theView, &camera);
  506.     GetGroupBBox( theDocument, &viewBBox);
  507.  
  508.     /*
  509.      *  If we have a point model, then the "viewBBox" would end up
  510.      *  being a "singularity" at the location of the point.  As
  511.      *  this bounding "box" is used in setting up the camera spec,
  512.      *  we get bogus input into Escher.
  513.      */
  514.     xSize = viewBBox.max.x - viewBBox.min.x;
  515.     ySize = viewBBox.max.y - viewBBox.min.y;
  516.     zSize = viewBBox.max.z - viewBBox.min.z;
  517.  
  518.     if (xSize <= kQ3RealZero &&
  519.         ySize <= kQ3RealZero &&
  520.         zSize <= kQ3RealZero)  {
  521.         viewBBox.max.x += 0.0001;
  522.         viewBBox.max.y += 0.0001;
  523.         viewBBox.max.z += 0.0001;
  524.         
  525.         viewBBox.min.x -= 0.0001;
  526.         viewBBox.min.y -= 0.0001;
  527.         viewBBox.min.z -= 0.0001;
  528.     }
  529.  
  530.     points[0] = viewBBox.min;
  531.     points[1] = viewBBox.max;
  532.  
  533.     Q3Point3D_AffineComb(points, weights, 2, documentGroupCenter);
  534.  
  535.     /*
  536.      *  The "from" point is on a vector perpendicular to the plane
  537.      *  in which the bounding box has greatest dimension.  As "up" is
  538.      *  always in the positive y direction, look at x and z directions.
  539.      */
  540.     xSize = viewBBox.max.x - viewBBox.min.x;
  541.     zSize = viewBBox.max.z - viewBBox.min.z;
  542.     
  543.     if (xSize > zSize) {
  544.         fromAxis = kQ3AxisZ;
  545.     } else {
  546.         fromAxis = kQ3AxisX;
  547.     }
  548.  
  549.     /*
  550.      *  Compute the length of the diagonal of the bounding box.
  551.      *
  552.      *  The hither and yon planes are adjusted so that the
  553.       *  diagonal of the bounding box is 7/8 the size of the
  554.       *  minimum dimension of the view frustum. The diagonal is used instead
  555.       *  of the maximum size (in x, y, or z) so that when you rotate
  556.       *  the object, the corners don't get clipped out.
  557.       */
  558.     Q3Point3D_Subtract(
  559.         &viewBBox.max,
  560.         &viewBBox.min,
  561.         &diagonalVector);
  562.  
  563.     maxDimension    =    Q3Vector3D_Length(&diagonalVector);
  564.     maxDimension    *=    8.0 / 7.0;
  565.     
  566.     ratio = 1.0 / maxDimension;
  567.             
  568.     *documentGroupScale = ratio;
  569.     
  570.     Q3Camera_GetPlacement(camera, &placement);
  571.  
  572.     Q3Point3D_Subtract(
  573.         &placement.cameraLocation,
  574.         &placement.pointOfInterest,
  575.         &viewVector);
  576.         
  577.     viewDistance = Q3Vector3D_Length(&viewVector);
  578.     
  579.     Q3Vector3D_Normalize(&viewVector, &normViewVector);
  580.     
  581.     Q3Vector3D_Scale(&normViewVector, 
  582.                      viewDistance - ratio * maxDimension/2.0,
  583.                      &eyeToFrontClip);
  584.                     
  585.     Q3Vector3D_Scale(&normViewVector, 
  586.                     viewDistance + ratio * maxDimension/2.0,
  587.                     &eyeToBackClip);
  588.  
  589.     hither     = Q3Vector3D_Length(&eyeToFrontClip);
  590.     yon     = Q3Vector3D_Length(&eyeToBackClip);
  591.     
  592.     fieldOfView = 2 * atan((ratio * maxDimension/2.0)/hither);
  593.  
  594.     range.hither                 = hither;
  595.     range.yon                     = yon;
  596.  
  597.     Q3Camera_SetRange(camera, &range);
  598.  
  599.     Q3ViewAngleAspectCamera_SetFOV(camera, fieldOfView);
  600.  
  601.     Q3ViewAngleAspectCamera_SetAspectRatio(
  602.         camera, (float) winWidth / (float) winHeight);
  603.  
  604.     Q3Object_Dispose(camera);
  605.     
  606.     return( *documentGroupCenter );
  607. }
  608.  
  609. //-----------------------------------------------------------------------
  610.  
  611. void SetWindowGeometry(WindowPtr win, short item)
  612. {
  613.     WindowObjHndl    obj;
  614.     DocumentHdl        theDocument;
  615.     TQ3Point3D        myOrigin = { 0, 0, 0 } ;
  616.     extern Boolean    Is3DWindow(WindowPtr);
  617.  
  618.     check(Is3DWindow(win));
  619.     check(theDocument != NULL);
  620.     
  621.     obj = (WindowObjHndl) GetWRefCon(win);
  622.     theDocument = GetDocumentHdl(obj);
  623.     require(theDocument != NULL, DocIsNULL);
  624.     
  625.     HLock((Handle) theDocument) ;
  626.     
  627.     if ((**theDocument).fModel != NULL) {
  628.         Q3Object_Dispose((**theDocument).fModel);
  629.         (**theDocument).fModel = nil;
  630.     }
  631.     
  632.     (**theDocument).fModel = BuildGeometry(item);
  633.     (**theDocument).fGroupScale = 1;                
  634.     (**theDocument).fGroupCenter = myOrigin;    
  635.     AdjustCamera(    theDocument,
  636.                     (win->portRect.right - win->portRect.left),
  637.                     (win->portRect.bottom - win->portRect.top) ) ;
  638.                     
  639.     HUnlock((Handle) theDocument);
  640.     SetPort(win);
  641.     InvalRect(&win->portRect);
  642.  
  643. DocIsNULL:
  644.     return;
  645. }        
  646.  
  647. //-----------------------------------------------------------------------
  648.  
  649. void SetWindowRenderer( WindowPtr win, short item )
  650. {
  651.     TQ3RendererObject        rendererObject;
  652.     TQ3DrawContextObject    myDrawContext;
  653.     WindowObjHndl            obj;
  654.     DocumentHdl                theDocument;
  655.  
  656.     obj = (WindowObjHndl) GetWRefCon(win);
  657.     theDocument = GetDocumentHdl(obj);
  658.     require(theDocument != NULL, DocIsNULL);
  659.     
  660.     HLock((Handle) theDocument) ;
  661.  
  662.  
  663.     switch (item) {
  664.         case iWF:
  665.             rendererObject = Q3Renderer_NewFromType( kQ3RendererTypeWireFrame );
  666.             Q3View_SetRendererByType( (*theDocument)->fView, kQ3RendererTypeWireFrame );
  667.             Q3Object_Dispose(rendererObject);
  668.             break;
  669.  
  670.         case iCTSW:
  671.             rendererObject = Q3Renderer_NewFromType(kQ3RendererTypeInteractive);
  672.             Q3InteractiveRenderer_SetDoubleBufferBypass(rendererObject, kQ3False);
  673.             Q3InteractiveRenderer_SetPreferences(rendererObject, kQAVendor_Apple, kQAEngine_AppleSW);
  674.             Q3View_SetRenderer((*theDocument)->fView,rendererObject);
  675.             break;
  676.             
  677.         case iCTHW:
  678.             rendererObject = Q3Renderer_NewFromType(kQ3RendererTypeInteractive);
  679.             Q3InteractiveRenderer_SetDoubleBufferBypass(rendererObject, kQ3True);
  680.             Q3InteractiveRenderer_SetPreferences(rendererObject, kQAVendor_BestChoice, kQAVendor_BestChoice);
  681.             Q3View_SetRenderer((*theDocument)->fView,rendererObject);                    
  682.             Q3Object_Dispose(rendererObject);
  683.             break;
  684.     }
  685.     InvalRect( &win->portRect ) ;
  686.  
  687.     HUnlock((Handle) theDocument);
  688.  
  689. DocIsNULL:
  690.     return;
  691. }
  692.  
  693. void SetWindowShading( WindowPtr win, short item )
  694. {
  695.     TQ3RendererObject        rendererObject;
  696.     TQ3DrawContextObject    myDrawContext;
  697.     WindowObjHndl            obj;
  698.     DocumentHdl                theDocument;
  699.  
  700.     obj = (WindowObjHndl) GetWRefCon(win);
  701.     theDocument = GetDocumentHdl(obj);
  702.     require(theDocument != NULL, DocIsNULL);
  703.     
  704.     HLock((Handle) theDocument) ;
  705.  
  706.  
  707.     switch(item){
  708.         case iFlat :
  709.             (**theDocument).fCurrentInterpolation = kQ3InterpolationStyleNone;
  710.             break;
  711.         case iVertex:
  712.             (**theDocument).fCurrentInterpolation = kQ3InterpolationStyleVertex;
  713.             break;
  714.         case iPixel:
  715.             (**theDocument).fCurrentInterpolation = kQ3InterpolationStylePixel;
  716.             break;
  717.     }
  718.             
  719.     InvalRect( &win->portRect ) ;
  720.  
  721.     HUnlock((Handle) theDocument);
  722.  
  723. DocIsNULL:
  724.     return;
  725. }
  726.  
  727.